<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8" />
        <meta
            name="viewport"
            content="width=device-width,initial-scale=1"
        />
        <title>PiP 学习助手 Demo</title>
        <style>
            body {
                font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
                padding: 18px;
                background: #f6f8fb;
                color: #111;
            }
            .row {
                display: flex;
                gap: 12px;
                align-items: center;
                margin-bottom: 12px;
            }
            button {
                padding: 8px 12px;
                border-radius: 6px;
                border: 1px solid #ddd;
                background: #fff;
                cursor: pointer;
            }
            button:disabled {
                opacity: 0.5;
                cursor: not-allowed;
            }
            #videoSrc {
                max-width: 60%;
            }
            canvas {
                border: 1px solid #ccc;
                background: #000;
            }
            #taskList {
                max-height: 120px;
                overflow: auto;
                background: #fff;
                padding: 8px;
                border-radius: 6px;
                border: 1px solid #e6e9ef;
            }
            .task {
                padding: 6px;
                border-bottom: 1px solid #f0f2f5;
            }
            .hint {
                color: #666;
                font-size: 13px;
            }
        </style>
    </head>
    <body>
        <h2>PiP 学习助手 Demo（单文件）</h2>

        <div class="row">
            <input
                id="file"
                type="file"
                accept="video/*"
            />
            <button id="loadExample">加载示例视频（若跨域失败请上传本地）</button>
            <button
                id="startPiP"
                disabled
            >
                进入 PiP（开始合成并打开 PiP）
            </button>
            <button
                id="stopPiP"
                disabled
            >
                退出 PiP
            </button>
        </div>

        <div class="row">
            <video
                id="videoSrc"
                controls
                playsinline
                style="max-width: 48%; height: 240px; background: #000"
            ></video>
            <canvas
                id="composite"
                width="640"
                height="360"
            ></canvas>
        </div>

        <div class="row">
            <div style="flex: 1">
                <div style="display: flex; gap: 8px; align-items: center; margin-bottom: 8px">
                    <label
                        ><input
                            id="autoTasks"
                            type="checkbox"
                            checked
                        />
                        模拟实时推送（模拟 WebSocket）</label
                    >
                    <label class="hint">(勾选将每 12 秒推送一个新任务)</label>
                </div>

                <div id="taskList"></div>
            </div>

            <div style="width: 320px">
                <div style="margin-bottom: 8px">
                    <strong>答题 / 同步</strong>
                    <div class="hint">注意：PiP 窗口目前无法直接接受页面上的文本输入，故在此处输入并提交，结果会同步到 PiP 显示。</div>
                </div>
                <div style="margin-bottom: 8px">
                    <label
                        >题号：
                        <select id="answerTaskSelect"></select>
                    </label>
                </div>
                <div style="margin-bottom: 8px">
                    <input
                        id="answerInput"
                        placeholder="在此输入答案"
                        style="width: 100%; padding: 8px; border-radius: 6px; border: 1px solid #ddd"
                    />
                </div>
                <div style="display: flex; gap: 8px">
                    <button
                        id="submitAnswer"
                        disabled
                    >
                        提交答案并同步
                    </button>
                    <button
                        id="markDone"
                        disabled
                    >
                        标记任务完成
                    </button>
                </div>
            </div>
        </div>

        <!-- 隐藏 video 用于播放 canvas 流并进入 PiP -->
        <video
            id="pipVideo"
            style="display: none"
            playsinline
            muted
        ></video>

        <script>
            /*
  PiP 学习助手 Demo 说明（简短）：
  - videoSrc: 用户加载的原始学习视频（本地或示例）
  - composite: 用于逐帧将视频与任务叠加绘制的 Canvas
  - pipVideo: 将 composite.captureStream() 设为 srcObject，并对 pipVideo 调用 requestPictureInPicture()
  - 任务推送通过模拟函数 pushTask() 实现（替代真实 WebSocket）
  - 浏览器限制：PiP 中不能直接进行 DOM 输入，需在主页面输入并同步
*/

            // DOM references
            const fileInput = document.getElementById("file")
            const loadExample = document.getElementById("loadExample")
            const videoSrc = document.getElementById("videoSrc")
            const composite = document.getElementById("composite")
            const ctx = composite.getContext("2d")
            const pipVideo = document.getElementById("pipVideo")

            const startPiPBtn = document.getElementById("startPiP")
            const stopPiPBtn = document.getElementById("stopPiP")

            const taskListEl = document.getElementById("taskList")
            const answerTaskSelect = document.getElementById("answerTaskSelect")
            const answerInput = document.getElementById("answerInput")
            const submitAnswer = document.getElementById("submitAnswer")
            const markDone = document.getElementById("markDone")
            const autoTasks = document.getElementById("autoTasks")

            let tasks = [] // {id, title, countdown, question, status, answer}
            let renderLoop = null
            let pipActive = false
            let compositeStream = null
            let taskPushTimer = null

            // 加载本地文件
            fileInput.addEventListener("change", (e) => {
                const f = e.target.files && e.target.files[0]
                if (f) {
                    videoSrc.src = URL.createObjectURL(f)
                    startPiPBtn.disabled = false
                }
            })

            // 加载示例视频（不保证跨域始终可用，若失败请上传本地视频）
            loadExample.addEventListener("click", () => {
                videoSrc.src = "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
                videoSrc.play().catch(() => {})
                startPiPBtn.disabled = false
            })

            // 启动合成并进入 PiP
            startPiPBtn.addEventListener("click", async () => {
                if (!document.pictureInPictureEnabled) {
                    alert("当前浏览器不支持 Picture-in-Picture（PiP）")
                    return
                }
                // 确保视频在播放（某些浏览器要求可播放）
                try {
                    await videoSrc.play()
                } catch (e) {
                    console.warn("videoSrc play failed", e)
                }

                // 设置 canvas 尺寸与视频一致（或按比例）
                composite.width = videoSrc.videoWidth || 640
                composite.height = videoSrc.videoHeight || 360

                
                // 获取 canvas 流并绑定到隐藏 pipVideo
                compositeStream = composite.captureStream(30)
                console.log(compositeStream)
                pipVideo.srcObject = compositeStream
                await pipVideo.play().catch(() => {})

                // 请求 PiP
                try {
                    await pipVideo.requestPictureInPicture()
                    pipActive = true
                    startPiPBtn.disabled = true
                    stopPiPBtn.disabled = false
                    submitAnswer.disabled = false
                    markDone.disabled = false
                    startRenderLoop()
                    startTaskPushIfNeeded()
                } catch (err) {
                    alert("进入 PiP 失败: " + err)
                }
            })

            // 退出 PiP
            stopPiPBtn.addEventListener("click", async () => {
                if (document.pictureInPictureElement) {
                    await document.exitPictureInPicture().catch(() => {})
                }
                stopRenderLoop()
                stopTaskPush()
                pipActive = false
                startPiPBtn.disabled = false
                stopPiPBtn.disabled = true
                submitAnswer.disabled = true
                markDone.disabled = true
            })

            // 当 PiP 关闭（用户通过窗口停止）时，停止 render loop
            document.addEventListener("leavepictureinpicture", () => {
                stopRenderLoop()
                stopTaskPush()
                pipActive = false
                startPiPBtn.disabled = false
                stopPiPBtn.disabled = true
            })

            // 渲染循环：把视频帧绘制到 canvas，并叠加任务信息
            function startRenderLoop() {
                if (renderLoop) return
                function loop() {
                    // 清屏并绘制视频
                    ctx.clearRect(0, 0, composite.width, composite.height)
                    try {
                        ctx.drawImage(videoSrc, 0, 0, composite.width, composite.height)
                    } catch (e) {
                        // 如果视频未准备好，会抛错，忽略
                    }

                    // 叠加 semi-transparent 背景用于任务显示
                    if (tasks.length > 0) {
                        // 找到第一个 active task 用于 PiP 显示
                        const t = tasks.find((x) => x.status !== "done") || tasks[tasks.length - 1]
                        drawTaskOnCanvas(t)
                    }

                    // 更新倒计时（每秒）
                    requestAnimationFrame(loop)
                }
                renderLoop = requestAnimationFrame(loop)
            }

            function stopRenderLoop() {
                if (!renderLoop) return
                cancelAnimationFrame(renderLoop)
                renderLoop = null
            }

            // 在 canvas 上绘制任务信息（位于右上角）
            function drawTaskOnCanvas(task) {
                if (!task) return
                const pad = 12,
                    boxW = 320,
                    boxH = 110
                ctx.save()
                // 背景
                ctx.fillStyle = "rgba(0,0,0,0.45)"
                ctx.fillRect(composite.width - boxW - pad, pad, boxW, boxH)
                // 标题
                ctx.fillStyle = "#fff"
                ctx.font = "18px sans-serif"
                wrapText(ctx, task.title, composite.width - boxW, pad + 26, boxW - 20, 20)
                // 倒计时
                ctx.font = "16px monospace"
                ctx.fillStyle = "#ffd766"
                ctx.fillText("倒计时: " + Math.max(0, Math.floor(task.countdown)) + "s", composite.width - boxW + 10, pad + boxH - 36)
                // 题目（简短）
                ctx.font = "14px sans-serif"
                ctx.fillStyle = "#fff"
                ctx.fillText("题: " + task.question, composite.width - boxW + 10, pad + boxH - 12)
                // 如果有答案则显示
                if (task.answer) {
                    ctx.fillStyle = "#9ef89e"
                    ctx.fillText("答: " + task.answer, composite.width - boxW + 10, pad + boxH - 60)
                }
                ctx.restore()
            }

            // 文本自动换行工具（简化）
            function wrapText(c, text, x, y, maxWidth, lineHeight) {
                const words = text.split(" ")
                let line = "",
                    curY = y
                for (let n = 0; n < words.length; n++) {
                    const testLine = line + words[n] + " "
                    const metrics = c.measureText(testLine)
                    if (metrics.width > maxWidth && n > 0) {
                        c.fillText(line, x + 10, curY)
                        line = words[n] + " "
                        curY += lineHeight
                    } else {
                        line = testLine
                    }
                }
                c.fillText(line, x + 10, curY)
            }

            // 模拟服务器推送任务（替代 WebSocket）
            function startTaskPushIfNeeded() {
                if (!autoTasks.checked) return
                if (taskPushTimer) return
                // push every 12 seconds
                taskPushTimer = setInterval(() => pushTask(mockTask()), 12000)
                // push one immediately
                pushTask(mockTask())
            }

            function stopTaskPush() {
                if (taskPushTimer) {
                    clearInterval(taskPushTimer)
                    taskPushTimer = null
                }
            }

            // 生成模拟任务对象
            let nextTaskId = 1
            function mockTask() {
                const id = "t" + nextTaskId++
                return {
                    id,
                    title: `练习题 ${id}`,
                    question: `请回答 ${id} 的示例问题？`,
                    countdown: 30, // 秒
                    status: "pending", // pending | answered | done
                    answer: "",
                }
            }

            // 推送任务到本地（模拟 WebSocket onmessage）
            function pushTask(task) {
                tasks.push(task)
                renderTaskList()
                updateAnswerSelect()
                // 每秒倒计时减少（简单实现）
                const timer = setInterval(() => {
                    if (task.countdown <= 0 || task.status === "done") {
                        clearInterval(timer)
                        if (task.countdown <= 0 && task.status === "pending") {
                            task.status = "expired"
                            renderTaskList()
                            updateAnswerSelect()
                        }
                        return
                    }
                    task.countdown -= 1
                }, 1000)
            }

            // 更新页面任务列表
            function renderTaskList() {
                taskListEl.innerHTML = ""
                tasks
                    .slice()
                    .reverse()
                    .forEach((t) => {
                        const div = document.createElement("div")
                        div.className = "task"
                        div.innerHTML = `<div><strong>${t.title}</strong> <span style="float:right">${t.status}</span></div>
                     <div style="font-size:13px;color:#666">倒计时: ${Math.max(0, Math.floor(t.countdown))}s</div>
                     <div style="margin-top:6px;font-size:14px">${t.question}</div>
                     <div style="margin-top:6px;color:#0a69ff;font-size:13px">答: ${t.answer || "（未作答）"}</div>`
                        taskListEl.appendChild(div)
                    })
            }

            // 更新答题选择下拉
            function updateAnswerSelect() {
                answerTaskSelect.innerHTML = ""
                tasks.forEach((t) => {
                    const opt = document.createElement("option")
                    opt.value = t.id
                    opt.textContent = `${t.title} [${t.status}]`
                    answerTaskSelect.appendChild(opt)
                })
                submitAnswer.disabled = tasks.length === 0
                markDone.disabled = tasks.length === 0
            }

            // 提交答案并同步（同步到 tasks 数据，会在 next canvas 渲染中显示）
            submitAnswer.addEventListener("click", () => {
                const id = answerTaskSelect.value
                const ans = answerInput.value.trim()
                if (!id || !ans) return alert("请选择任务并输入答案")
                const t = tasks.find((x) => x.id === id)
                if (!t) return
                t.answer = ans
                t.status = "answered"
                renderTaskList()
                // 模拟把结果发送给后端（这里仅在 console 显示）
                console.log("同步答案到后端：", { taskId: t.id, answer: t.answer })
            })

            // 标记任务完成
            markDone.addEventListener("click", () => {
                const id = answerTaskSelect.value
                if (!id) return
                const t = tasks.find((x) => x.id === id)
                if (!t) return
                t.status = "done"
                renderTaskList()
                updateAnswerSelect()
            })

            // 当用户切换 autoTasks 选框时启动/停止推送
            autoTasks.addEventListener("change", () => {
                if (autoTasks.checked) startTaskPushIfNeeded()
                else stopTaskPush()
            })

            // 页面卸载时清理
            window.addEventListener("beforeunload", () => {
                stopRenderLoop()
                stopTaskPush()
                if (document.pictureInPictureElement) document.exitPictureInPicture().catch(() => {})
            })
        </script>
    </body>
</html>
